/*
 * HTTP Server with libcurl support
 * Author: Qoder
 * Description: Simple HTTP server with CGI support, file download, and ping-pong functionality
 * Note: This server uses standard socket programming for HTTP handling, with optional libcurl support for client operations
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/stat.h>
#include <time.h>

#include "server_functions.h"
#include "cgi_functions.h"

#define DEFAULT_PORT 8080
#define BUFFER_SIZE 4096
#define MAX_CONNECTIONS 10

static int server_fd = -1;
static volatile int server_running = 1;

void signal_handler(int sig) {
    printf("\n[INFO] Received signal %d, shutting down server...\n", sig);
    server_running = 0;
    if (server_fd >= 0) {
        close(server_fd);
    }
}

int main(int argc, char *argv[]) {
    int port = DEFAULT_PORT;
    int client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    pthread_t thread_id;
    
    // Parse command line arguments
    if (argc > 1) {
        port = atoi(argv[1]);
        if (port <= 0 || port > 65535) {
            fprintf(stderr, "Error: Invalid port number %d\n", port);
            return 1;
        }
    }
    
    // Set up signal handlers
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    // Create socket
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket creation failed");
        return 1;
    }
    
    // Set socket options
    int opt = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        perror("setsockopt failed");
        close(server_fd);
        return 1;
    }
    
    // Configure server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port);
    
    // Bind socket
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        close(server_fd);
        return 1;
    }
    
    // Listen for connections
    if (listen(server_fd, MAX_CONNECTIONS) < 0) {
        perror("listen failed");
        close(server_fd);
        return 1;
    }
    
    printf("HTTP Server started on port %d\n", port);
    printf("Available endpoints:\n");
    printf("  GET  /ping          - Ping-pong test\n");
    printf("  GET  /cgi/time      - Get system time (JSON)\n");
    printf("  GET  /cgi/status    - Get system status (JSON)\n");
    printf("  GET  /download/*    - Download files\n");
    printf("  POST /cgi/echo      - Echo POST data (JSON)\n");
    printf("\nPress Ctrl+C to stop the server\n\n");
    
    // Main server loop
    while (server_running) {
        client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
        if (client_fd < 0) {
            if (server_running) {
                perror("accept failed");
            }
            continue;
        }
        
        // Create client info structure
        client_info_t *client_info = (client_info_t*)malloc(sizeof(client_info_t));
        if (!client_info) {
            close(client_fd);
            continue;
        }
        
        client_info->socket_fd = client_fd;
        client_info->client_addr = client_addr;
        
        // Handle client in a new thread
        if (pthread_create(&thread_id, NULL, handle_client, client_info) != 0) {
            perror("pthread_create failed");
            free(client_info);
            close(client_fd);
            continue;
        }
        
        // Detach thread to avoid memory leaks
        pthread_detach(thread_id);
    }
    
    close(server_fd);
    printf("[INFO] Server stopped\n");
    return 0;
}